Skip to content
标签
安全
字数
2998 字
阅读时间
17 分钟

配置过滤器

java

import com.alibaba.fastjson.JSON;
import com.commnetsoft.commons.Result;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.zuul.RouteRuntimeException;
import com.commnetsoft.zuul.service.WebMvcRouteService;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Map;


/**
 * 前置路由JWT 过滤器<br/>
 * 内部地址.fn统一禁止外部访问
 * <br/>
 * pre: 请求执行之前
 * <p>
 * route: 处理请求,进行路由
 * <p>
 * post: 请求处理完成后执行
 * <p>
 * error: 出现错误时执行
 * author Brack.zhu
 * date 2019/3/27
 */
@Component
public class ZuulJwtFilter extends ZuulFilter {

    private Logger log = LoggerFactory.getLogger(ZuulJwtFilter.class);

    @Autowired
    private WebMvcRouteService webMvcRouteService;

    /**
     * 前置过滤器
     *
     * @return
     */
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    /**
     * 装载顺序越小越先执行
     *
     * @return
     */
    @Override
    public int filterOrder() {
        return FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER;
    }

    /**
     * 过滤器是否生效
     *
     * @return true需要权限校验,false不需要用户校验即可访问
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }


    /**
     * 业务逻辑
     * 只有过滤器生效,才会进入到该方法
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        try {
            HttpServletRequest request = requestContext.getRequest();
            Map<String, String> verifyData = webMvcRouteService.verifyUri(request);
            if (null != verifyData) {
                //认证头数据
                Iterator<Map.Entry<String, String>> entries = verifyData.entrySet().iterator();
                while (entries.hasNext()) {
                    Map.Entry<String, String> entry = entries.next();
                    requestContext.addZuulRequestHeader(entry.getKey(), URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name()));
                }
                //TODO 移除请求头数据,如jwt
            }
        }catch (RouteRuntimeException rre) {
            requestInvalid(requestContext, rre);
        }catch (MicroRuntimeException mre){
            requestInvalid(requestContext,new RouteRuntimeException(mre, HttpStatus.FORBIDDEN));
        }catch (Exception e) {
            log.error("前置路由过滤器异常:", e);
            // ZuulException 返回数据格式
            // {
            //  "timestamp": "2020-09-28 14:41:11",
            //  "status": 500,
            //  "error": "Internal Server Error",
            //  "message": "exception message"
            //}
            throw new ZuulException(e, HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getLocalizedMessage());
        }
        return null;
    }

    /**
     * 请求无效处理
     *
     * @param requestContext
     * @param routeRuntimeException
     */
    public void requestInvalid(RequestContext requestContext, RouteRuntimeException routeRuntimeException) {
        String respJson=JSON.toJSONString(Result.create(routeRuntimeException)) ;
        requestInvalid(requestContext, routeRuntimeException.getStatus(),respJson);
    }

    /**
     * 请求无效处理
     *
     * @param requestContext
     * @param httpStatus    返回http错误码
     * @param  respBody    返回的内容
     */
    public void requestInvalid(RequestContext requestContext, HttpStatus httpStatus,String respBody) {
        // 过滤该请求,不对其进行路由
        requestContext.setSendZuulResponse(false);
        //错误代码
        requestContext.setResponseStatusCode(httpStatus.value());
        if(StringUtils.isNotBlank(respBody)){
            requestContext.setResponseBody(respBody);
        }
        requestContext.getResponse().setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
    }
}

处理类

java

import com.commnetsoft.auth.model.HttpReqHead;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.utils.HttpRequestUtil;
import com.commnetsoft.zuul.RouteRuntimeException;
import com.commnetsoft.zuul.UriType;
import com.commnetsoft.zuul.uri.IUriHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * WebMvc路由服务<br/>
 * 使用需要在Configuration中声明
 *
 * @author Brack.zhu
 * @date 2020/6/3
 */
@Service
public class WebMvcRouteService extends RouteService {

    private Logger log = LoggerFactory.getLogger(WebMvcRouteService.class);

    /**
     * URI地址权限校验
     *
     * @return
     */
    public Map<String, String> verifyUri(HttpServletRequest servletRequest) throws RouteRuntimeException {
        String uri = servletRequest.getRequestURI();
        String method = servletRequest.getMethod();
        UriType uriType = super.convertUri(uri);
        List<String> keys = super.headerKeys(uriType);
        Map<String, String> headers = getHeaders(servletRequest, keys);
        String contentType = servletRequest.getContentType();
        InputStream inputStream = null;
        if (isBodyData(uriType, contentType)) {
            try {
                inputStream = servletRequest.getInputStream();
            } catch (IOException e) {
                if (log.isDebugEnabled()) {
                    log.debug("获取{}输入流异常", uri);
                }
            }
        }
        return super.verifyUri(uri, uriType, method, headers, inputStream);
    }

    /**
     * 获取指定的头数据
     *
     * @param servletRequest
     * @param keys
     * @return
     */
    public Map<String, String> getHeaders(HttpServletRequest servletRequest, List<String> keys) {
        if (null == keys) {
            return null;
        }
        Map<String, String> headers = new HashMap<>();
        for (String key : keys) {
            if (IUriHandler.EXTEND_HEADER_REQUEST_REMOTE_ADDRESS.equals(key)) {
                //特殊
                String headerVal = servletRequest.getRemoteAddr();
                headers.put(key, headerVal);
            } else if (HttpReqHead.token.getValue().equals(key) || HttpReqHead.token_old.getValue().equals(key)) {
                //特殊 token 头获取失败从cookie中取
                String headerVal = servletRequest.getHeader(key);
                if (StringUtils.isEmpty(headerVal)) {
                    headerVal = HttpRequestUtil.getCookieVal(servletRequest, key);
                }
                headers.put(key, headerVal);
            } else {
                String headerVal = servletRequest.getHeader(key);
                headers.put(key, headerVal);
            }
        }
        return headers;
    }

}



import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroRuntimeException;

import com.commnetsoft.zuul.RouteRuntimeException;
import com.commnetsoft.zuul.UriType;
import com.commnetsoft.zuul.feign.AuthResApi;
import com.commnetsoft.zuul.uri.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;

import java.io.InputStream;
import java.util.List;
import java.util.Map;

/**
 * 路由业务服务<br/>
 * 顺序变化会对业务有影响<br/>
 * <ol>
 *     <li>resource</li>
 *     <li>open</li>
 *     <li>external</li>
 *     <li>internal</li>
 * </ol>
 *
 * @author Brack.zhu
 * @date 2020/5/27
 */
public abstract class RouteService {

    @Autowired
    protected AuthResApi authResApi;

    @Autowired
    protected InternalApiUriHandler internalApiUriHandler;

    @Autowired
    protected ExternalApiUriHandler externalApiUriHandler;

    @Autowired
    protected OpenApiUriHandler openApiUriHandler;

    @Autowired
    protected ResourceUriHandler resourceUriHandler;

    @Autowired
    protected WebsocketUriHandler websocketUriHandler;


    private Logger log = LoggerFactory.getLogger(RouteService.class);


    /**
     * 解析JWT
     *
     * @param jwt
     * @return
     * @throws MicroRuntimeException
     */
    public Map<String, String> parseJwt(String jwt) throws MicroRuntimeException {
        return authResApi.jwtParse(jwt).tryData();
    }


    /**
     * URI地址权限校验<br>
     *
     * @return
     */
    public Map<String, String> verifyUri(String uri, UriType uriType, String method, Map<String, String> headers, InputStream in) throws RouteRuntimeException {
        IUriHandler uriHandler = getUriHandler(uriType);
        if (null != uriHandler) {
            return uriHandler.verifyUri(uri, method, headers, in);
        } else {
            log.warn("根据{},{}获取处理器失败,", uriType, uri);
            throw new RouteRuntimeException(CommonError.unsupport,"未获取对应URI过滤器:"+uriType,HttpStatus.FORBIDDEN);
        }
    }

    /**
     * 获取地址类型
     * 判断条件根据预判的调用程度排先后顺序
     *
     * @param uri
     * @return
     */
    public UriType convertUri(String uri) {
        if (websocketUriHandler.isSupport(uri)){
            return  websocketUriHandler.handlerType();
        }
        if (resourceUriHandler.isSupport(uri)) {
            return resourceUriHandler.handlerType();
        }
        if (openApiUriHandler.isSupport(uri)) {
            return openApiUriHandler.handlerType();
        }
        if (externalApiUriHandler.isSupport(uri)) {
            return externalApiUriHandler.handlerType();
        }
        if (internalApiUriHandler.isSupport(uri)) {
            return internalApiUriHandler.handlerType();
        }
        return UriType.UNDEFINED_URI;
    }

    /**
     * 根据URI类型获取请求头参数key集合
     *
     * @param uritype
     * @return
     */
    public List<String> headerKeys(UriType uritype) {
        IUriHandler uriHandler = getUriHandler(uritype);
        if (null != uriHandler) {
            return uriHandler.headerKeys();
        }
        return null;
    }

    /**
     * 根据URI类型判断是否需要请求数据
     *
     * @param uritype
     * @param contentType
     * @return
     */
    public boolean isBodyData(UriType uritype,String contentType) {
        IUriHandler uriHandler = getUriHandler(uritype);
        if (null != uriHandler) {
            return uriHandler.isBodyData(contentType);
        }
        return false;
    }

    /**
     * 根据URI类型获取处理对象
     *
     * @param uritype
     * @return
     */
    public IUriHandler getUriHandler(UriType uritype) {
        switch (uritype) {
            case WEBSOCKET_URI:
                return websocketUriHandler;
            case OPEN_API_URI:
                return openApiUriHandler;
            case INTERNAL_API_URI:
                return internalApiUriHandler;
            case EXTERNAL_API_URI:
                return externalApiUriHandler;
            case RESOURCE_URI:
                return resourceUriHandler;
            default:
                return null;
        }
    }

    /**
     * 是否内部接口地址类型
     *
     * @param uri
     * @return
     */
    public boolean isInternalApiUri(String uri) {
        return internalApiUriHandler.isSupport(uri);
    }

    /**
     * 是否外部接口地址类型
     *
     * @param uri
     * @return
     */
    public boolean isExternalApiUri(String uri) {
        return externalApiUriHandler.isSupport(uri);
    }

    /**
     * 是否开放接口地址类型
     *
     * @param uri
     * @return
     */
    public boolean isOpenApiUri(String uri) {
        return openApiUriHandler.isSupport(uri);
    }

    /**
     * 是否资源地址类型
     *
     * @param uri
     * @return
     */
    public boolean isResourceUri(String uri) {
        return resourceUriHandler.isSupport(uri);
    }

}

地址处理类

java

import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.CoreConstant;
import com.commnetsoft.zuul.RouteRuntimeException;
import com.commnetsoft.zuul.UriType;

import java.io.InputStream;
import java.util.List;
import java.util.Map;

/**
 * 地址处理器接口
 *
 * @author Brack.zhu
 * @date 2020/6/2
 */
public interface IUriHandler {

    /**
     * 获取request远程地址头 key---特殊未经过负载层的
     */
    String EXTEND_HEADER_REQUEST_REMOTE_ADDRESS = "Extend_Request_Remote_Address_Header_Key";

    /**
     * 处理器支持处理类型
     *
     * @return
     */
    UriType handlerType();

    /**
     * 是否支持的地址类型
     *
     * @param uri
     * @return
     */
    boolean isSupport(String uri);

    /**
     * 获取该处理器需要的头数据的key集合
     *
     * @return
     */
    List<String> headerKeys();

    /**
     * 判断该处理器是否需求请求体数据
     * @param  contentType 请求类型
     * @return
     */
    boolean isBodyData(String contentType);

    /**
     * URI地址权限校验
     *
     * @param uri
     * @param method
     * @param headers
     * @param in
     * @return 有效jwt对应的信息
     * @throws RouteRuntimeException 校验异常
     */
    Map<String, String> verifyUri(String uri, String method, Map<String, String> headers, InputStream in);

    /**
     * 获取头IP数据
     *
     * @param headers
     * @return
     */
    default String getHeaderIp(Map<String, String> headers) {
        if (null == headers) {
            return null;
        }
        String ip = headers.get(CoreConstant.Http.HEADER_REAL_IP);
        if (StringUtils.isEmpty(ip)) {
            ip = headers.get(EXTEND_HEADER_REQUEST_REMOTE_ADDRESS);
        }
        return ip;
    }

}
java

import com.commnetsoft.auth.model.HttpReqHead;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UriUtil;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.zuul.RouteRuntimeException;
import com.commnetsoft.zuul.UriType;
import com.commnetsoft.zuul.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 外部接口地址处理器实现类
 *
 * @author Brack.zhu
 * @date 2020/6/2
 */
@Component
public class ExternalApiUriHandler implements IUriHandler {

    public static final String JWT = "jwt";

    @Autowired
    private AuthService authService;

    private List<String> headerKeys;

    public ExternalApiUriHandler() {
        headerKeys = new ArrayList<>(2);
        headerKeys.add(HttpReqHead.token.getValue());
        //兼容老的
        headerKeys.add(HttpReqHead.token_old.getValue());
    }

    @Override
    public UriType handlerType() {
        return UriType.EXTERNAL_API_URI;
    }

    @Override
    public List<String> headerKeys() {
        return headerKeys;
    }

    @Override
    public boolean isBodyData(String contentType) {
        return false;
    }

    @Override
    public Map<String, String> verifyUri(String uri, String method, Map<String, String> headers, InputStream in) {
        try {
            String jwt = getHeaderToken(headers);
            return authService.uriVerify(uri, method, jwt);
        } catch (MicroRuntimeException mre) {
            if (mre.getCode().toLowerCase().contains(JWT)) {
                throw new RouteRuntimeException(mre,HttpStatus.NOT_ACCEPTABLE);
            } else {
                throw new RouteRuntimeException(mre,HttpStatus.FORBIDDEN);
            }
        }catch (Exception e){
            throw new RouteRuntimeException(CommonError.internal_error,e.getMessage(),HttpStatus.FORBIDDEN);
        }
    }

    @Override
    public boolean isSupport(String uri) {
        String ext = UriUtil.getFileExtension(uri);
        if (StringUtils.isBlank(ext)) {
            //没有后缀的定义为外部接口
            return true;
        }
        return false;
    }

    /**
     * 获取{@link HttpReqHead#token} 值
     * @param headers
     * @return
     */
    String getHeaderToken(Map<String,String> headers){
        if(null==headers){
            return null;
        }
        String jwt=headers.get(HttpReqHead.token.getValue());
        //兼容老的TOKEN头参数
        if(StringUtils.isBlank(jwt)){
            jwt=headers.get(HttpReqHead.token_old.getValue());
        }
        return jwt;
    }
}
java

import com.commnetsoft.auth.model.HttpReqHead;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UriUtil;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.core.CoreConstant;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.zuul.RouteRuntimeException;
import com.commnetsoft.zuul.UriType;
import com.commnetsoft.zuul.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 内部接口地址处理器实现类<br/>
 * http://127.0.0.1:8080/auth/test.fn<br/>
 * 调用方需在Http头中传递<br>
 * X-Commnet-Manage:  密钥 MD5 字符串
 *
 * @author Brack.zhu
 * @date 2020/6/2
 */
@Component
public class InternalApiUriHandler implements IUriHandler {

    /**
     * Feign内部调用URL接口后缀 .fn
     */
    public static final String INTERNAL_URL_SUFFIX = "fn";

    private List<String> headerKeys;

    @Autowired
    private AuthService authService;

    public InternalApiUriHandler() {
        headerKeys = new ArrayList<>(3);
        headerKeys.add(HttpReqHead.manage.getValue());
        headerKeys.add(CoreConstant.Http.HEADER_REAL_IP);
        //未经过Nginx
        headerKeys.add(EXTEND_HEADER_REQUEST_REMOTE_ADDRESS);
    }

    @Override
    public UriType handlerType() {
        return UriType.INTERNAL_API_URI;
    }

    @Override
    public List<String> headerKeys() {
        return headerKeys;
    }

    @Override
    public boolean isBodyData(String contentType) {
        return false;
    }

    @Override
    public Map<String, String> verifyUri(String uri, String method, Map<String, String> headers, InputStream in) {
        //是否管理后台调用
        try {
            String manageKey = getHeaderManage(headers);
            if (StringUtils.isBlank(manageKey)) {
                throw new RouteRuntimeException(CommonError.illegal_operation,"非法访问,无管理密钥鉴权", HttpStatus.FORBIDDEN);
            }
            String ip = getHeaderIp(headers);
            return authService.internalUriVerify(uri, method, manageKey, ip);
        }catch (RouteRuntimeException rre){
            throw rre;
        }catch (MicroRuntimeException mre) {
            throw new RouteRuntimeException(mre, HttpStatus.FORBIDDEN);
        }
    }

    @Override
    public boolean isSupport(String uri) {
        String ext = UriUtil.getFileExtension(uri);
        if (StringUtils.isNotBlank(ext) && INTERNAL_URL_SUFFIX.equals(ext)) {
            return true;
        }
        return false;
    }

    String getHeaderManage(Map<String, String> headers) {
        if (null == headers) {
            return null;
        }
        return headers.get(HttpReqHead.manage.getValue());
    }

}
java

import com.commnetsoft.auth.model.HttpReqHead;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UriUtil;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.core.CoreConstant;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.zuul.RouteRuntimeException;
import com.commnetsoft.zuul.UriType;
import com.commnetsoft.zuul.service.AuthService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 开放接口地址处理器实现类
 *
 * @author Brack.zhu
 * @date 2020/6/2
 */
@Component
public class OpenApiUriHandler implements IUriHandler {

    @Autowired
    private AuthService authService;

    private List<String> headerKeys;

    private Logger log = LoggerFactory.getLogger(OpenApiUriHandler.class);

    public OpenApiUriHandler() {
        headerKeys = new ArrayList<>(6);
        headerKeys.add(HttpReqHead.servicecode.getValue());
        headerKeys.add(HttpReqHead.time.getValue());
        headerKeys.add(HttpReqHead.sign.getValue());
        //兼容老的
        headerKeys.add(HttpReqHead.sign_old.getValue());
        headerKeys.add(CoreConstant.Http.HEADER_REAL_IP);
        headerKeys.add(EXTEND_HEADER_REQUEST_REMOTE_ADDRESS);
    }

    /**
     * 开放接口地址前缀
     */
    public static final String OPEN_API_PATH = "open";

    @Override
    public UriType handlerType() {
        return UriType.OPEN_API_URI;
    }

    @Override
    public List<String> headerKeys() {
        return headerKeys;
    }

    @Override
    public boolean isBodyData(String contentType) {
        //application/json;charset=UTF-8 类型请求传入 请求流
        if (StringUtils.isBlank(contentType) ||
                (contentType.startsWith(MediaType.APPLICATION_JSON_UTF8_VALUE)
                        || contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)
                        || contentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED_VALUE))) {
            return true;
        }
        log.warn("开放接口请求contentType:{}类型无效,不获取请求body流;仅支持空和{},{},{}", contentType, MediaType.APPLICATION_JSON_UTF8_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        return false;
    }

    @Override
    public Map<String, String> verifyUri(String uri, String method, Map<String, String> headers, InputStream in) {
        try {
            String sign = getHeaderSign(headers);
            if (StringUtils.isEmpty(sign)) {
                //无签名数据直接返回
                throw new RouteRuntimeException(CommonError.illegal_args,"无sign签名数据",HttpStatus.FORBIDDEN);
            }
            String serviceCode = getHeaderServiceCode(headers);
            String time = getHeaderTime(headers);
            String ip = getHeaderIp(headers);
            return authService.openUriVerify(serviceCode, time, sign, ip, uri, method, in);
        } catch (RouteRuntimeException rre) {
            log.error("URI地址权限校验路由错误:", rre);
            throw rre;
        } catch (MicroRuntimeException mre) {
            log.error("URI地址权限校验错误:", mre);
            throw new RouteRuntimeException(mre,HttpStatus.FORBIDDEN);
        } catch (Exception e) {
            log.error("URI地址权限校验内部错误:", e);
            throw new RouteRuntimeException(CommonError.internal_error,e.getMessage(),HttpStatus.FORBIDDEN);
        }
    }

    @Override
    public boolean isSupport(String uri) {
        try {
            String[] paths = UriUtil.getPaths(new URI(uri));
            if (null != paths && paths.length > 2) {
                // 格式如 /open/*****
                String path = paths[0];
                if (OPEN_API_PATH.equals(path)) {
                    return true;
                }
                // 格式如 /api/open/*****
                path = paths[1];
                if (OPEN_API_PATH.equals(path)) {
                    return true;
                }
            }

        } catch (URISyntaxException e) {
            log.error("URL地址({})转换异常:", uri, e);
        }
        return false;
    }

    String getHeaderServiceCode(Map<String, String> headers) {
        if (null == headers) {
            return null;
        }
        return headers.get(HttpReqHead.servicecode.getValue());
    }

    String getHeaderTime(Map<String, String> headers) {
        if (null == headers) {
            return null;
        }
        return headers.get(HttpReqHead.time.getValue());
    }

    String getHeaderSign(Map<String, String> headers) {
        if (null == headers) {
            return null;
        }
        String sign = headers.get(HttpReqHead.sign.getValue());
        if (StringUtils.isBlank(sign)) {
            //兼容老的
            sign = headers.get(HttpReqHead.sign_old.getValue());
        }
        return sign;
    }


}
java

import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UriUtil;
import com.commnetsoft.zuul.UriType;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 资源地址处理器实现类<br/>
 *  <ui>
 *      <li>.ws 放行</li>
 *  </ui>
 *
 *
 * @author Brack.zhu
 * @date 2020/6/2
 */
@Component
public class ResourceUriHandler implements IUriHandler {



    /**
     * 排除放行地址后缀集合
     */
    public List<String> excludeFileExtensions = null;

    /**
     * 白名单地址集合
     */
    public List<String> whiteUris = null;

    /**
     * 黑名单地址集合
     */
    public List<String> blackUris = null;

    public ResourceUriHandler() {
        excludeFileExtensions = new ArrayList<>(1);
        //.fn地址不放行
        excludeFileExtensions.add(InternalApiUriHandler.INTERNAL_URL_SUFFIX);

        whiteUris = new ArrayList<>(4);
        whiteUris.add("/v2/api-docs");
        whiteUris.add("/swagger-resources");
        whiteUris.add("/swagger-resources/configuration/security");
        whiteUris.add("/swagger-resources/configuration/ui");

    }

    @Override
    public UriType handlerType() {
        return UriType.RESOURCE_URI;
    }

    @Override
    public List<String> headerKeys() {
        return null;
    }

    @Override
    public boolean isBodyData(String contentType) {
        return false;
    }

    @Override
    public Map<String, String> verifyUri(String uri, String method, Map<String, String> headers, InputStream in) {
        //资源类型直接放行
        return null;
    }

    @Override
    public boolean isSupport(String uri) {
        //白名单地址本处理器处理
        if (isWhiteUri(uri)) {
            return true;
        }
        //黑名单地址本处理不处理---交给其他处理器处理
        if (isBlackUri(uri)) {
            return false;
        }
        String ext = UriUtil.getFileExtension(uri);
        if (StringUtils.isNotBlank(ext) && !excludeFileExtensions.contains(ext)) {
            //带资源文件类型且不是内部接口的统统放行
            return true;
        }
        return false;
    }

    /**
     * 是否白名单
     *
     * @param uri
     * @return
     */
    boolean isWhiteUri(String uri) {
        if (null != whiteUris) {
            for (String whiteUri : whiteUris) {
                if (uri.endsWith(whiteUri)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 是否黑名单
     *
     * @param uri
     * @return
     */
    boolean isBlackUri(String uri) {
        if (null != blackUris) {
            for (String blackUri : blackUris) {
                if (uri.endsWith(blackUri)) {
                    return true;
                }
            }
        }
        return false;
    }

}
java

import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.commons.utils.UriUtil;
import com.commnetsoft.core.CommonError;
import com.commnetsoft.zuul.RouteRuntimeException;
import com.commnetsoft.zuul.UriType;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.util.List;
import java.util.Map;

/**
 * Websocket 地址处理器
 * @author Brack.zhu
 * @date 2020/6/16
 */
@Component
public class WebsocketUriHandler implements IUriHandler{

    /**
     * WEBSOCKET内部调用URL接口后缀 .ws
     */
    public static final String WEBSOCKET_URL_SUFFIX = ".ws";

    @Override
    public UriType handlerType() {
        return UriType.WEBSOCKET_URI;
    }

    @Override
    public boolean isSupport(String uri) {
        String ext = UriUtil.getFileExtension(uri);
        if (StringUtils.isNotBlank(ext) && WEBSOCKET_URL_SUFFIX.equals(ext)) {
            //ws接口类型支持
            return true;
        }
        return false;
    }

    @Override
    public List<String> headerKeys() {
        return null;
    }

    @Override
    public boolean isBodyData(String contentType) {
        return false;
    }

    @Override
    public Map<String, String> verifyUri(String uri, String method, Map<String, String> headers, InputStream in) {
        //该路由服务禁止一切ws接口访问,Websocket访问使用Gateway路由
        throw new RouteRuntimeException(CommonError.illegal_operation,"该路由不支持WS通讯",HttpStatus.FORBIDDEN);
    }
}